07 de Junio, 2017
Hasta el momento hemos hablado de la creación de documentos mediante R Markdown, interactivos o no, pensando en un uso local.
Estamos en la sociedad de la información e internet lo domina todo. ¿Podemos utilizar internet para ayudar en la investigación reproducible?
Shiny es una herramienta perfecta para compartir nuestros estudios, permitiendo el acceso a la información. Esto genera numerosos beneficios:
Paso 1. Abrimos RStudio.
Paso 2. Instalamos el paquete "shiny" desde CRAN (en caso de no haberlo instalado previamente):
install.packages("shiny", dependencies = TRUE)
Paso 3. Seleccionamos File >> New File >> Shiny Web App….
Paso 4. Indicamos el nombre de la aplicación, el número de archivos que queremos y el directorio de creación.
Si no cerramos la app, esta se queda ejecutándose en R y no podremos seguir trabajando.
Para crear una aplicación Shiny es suficiente con tener los scripts ui.R y server.R (app.R) dentro de la misma carpeta. El nombre de estos scripts no se puede cambiar.
La estructura es la siguiente:
1. Estructura general (layouts de página)
2. División de la página (layouts)
3. Contenido de la página (widgets)
Estructura general
Las funciones que definen la estructura general de la página suelen tener nombres ...Page().
División de la página
Las funciones para definir el diseño de la página suelen tener nombres ...Layout().
División de la página por paneles
Las funciones para definir paneles en la página suelen tener nombres ...Panel().
Para el diseño debemos pensar donde se va a reproducir nuestra aplicación:
Página en blanco, default. La mayoría de aplicaciones deben utilizar fluidPage() en combinación con otros Layouts.
ui <- fluidPage(
titlePanel("Shiny - fluidPage")
)
server <- function(input, output) {
}
shinyApp(ui, server)
fluidPage(..., title = NULL, responsive = NULL, theme = NULL)
Página en blanco. bootstrapPage() está pensada para usuarios que tienen dominio en HTML / CSS y saben diseñar webs con Bootstrap.
ui <- bootstrapPage(
titlePanel("Shiny - bootstrapPage")
)
server <- function(input, output) {
}
shinyApp(ui, server)
Notas:
Los elementos de la página se definen de arriba abajo.
La separación entre los elementos es con comas.
Los layouts se pueden combinar unos dentro de otros, anidados.
Gran flexibilidad en la configuración del UI.
Página con barra lateral. Usualmente se emplea para colocar selectores que manipulará el usuario y darán como respuesta una salida en el panel principal.
ui <- fluidPage(
titlePanel("Shiny - sidebarLayout"),
sidebarLayout(
sidebarPanel(
sliderInput("obs", "Número de observaciones:", min = 0, max = 1000, value = 500)
),
mainPanel(
plotOutput("distPlot")
)))
server <- function(input, output) {
output$distPlot <- renderPlot({
hist(rnorm(input$obs))
})}
shinyApp(ui, server)
Página dividida verticalmente que permite introducir contenido por filas.
ui <- fluidPage(
titlePanel("Shiny - verticalLayout"),
verticalLayout(
a(href="http://example.com/link1", "Link Primero"),
a(href="http://example.com/link2", "Link Segundo"),
a(href="http://example.com/link3", "Link Tercero")
)
)
server <- function(input, output) {}
shinyApp(ui, server)
Definimos una columna de 12 unidades de dimensión. Nos permite asegurar la posición, horizontalmente, de los elementos definidos en ella.
fluidRow() nos permite asegurar que los elementos definidos están en la misma fila. Usualmente su utilización viene combinada con la de column().ui <- fluidPage(
titlePanel("Shiny - column() / fluidRow()"),
fluidRow(
column(width = 4, wellPanel("Columna de 4 unidades")),
column(width = 3, offset = 2, wellPanel("Columna de 3 unidades"))
))
shinyApp(ui, server = function(input, output) { })
Dividimos la página en dos partes, marcadas por cellWidths.
ui <- fluidPage(
titlePanel("Shiny - splitLayout"),
splitLayout(cellWidths = c("50%", "50%"),
plotOutput("plot1"),
plotOutput("plot2")
)
)
server <- function(input, output) {
output$plot1 <- renderPlot(plot(cars))
output$plot2 <- renderPlot(plot(pressure))
}
shinyApp(ui, server)
Definimos un panel condicional, que aparecerá dependiendo de que se cumpla cierta condición.
ui <- fluidPage(titlePanel("Shiny - conditionalPanel"),
sidebarPanel(
selectInput("plotType", "Plot Type", c(Scatter = "scatter", Histogram = "hist")),
conditionalPanel(condition = "input.plotType == 'hist'",
selectInput("breaks", "Breaks", c("Sturges", "[Custom]" = "custom")),
conditionalPanel(condition = "input.breaks == 'custom'",
sliderInput("breakCount", "Break Count", min = 1, max = 1000, value = 10)
)
)
)
)
server <- function(input, output) {}
shinyApp(ui, server)
Si condicionamos por una variable definida por el usuario:
- Nos referiremos a la variable como input.xxx, NO usaremos input$xxx.
Crea una página que tiene una barra de navegación en la parte superior
ui <- navbarPage("Shiny - navbarPage",
tabPanel("Primera Página", plotOutput("plot1")),
tabPanel("Segunda Página", plotOutput("plot2"))
)
server <- function(input, output) {
output$plot1 <- renderPlot(plot(cars))
output$plot2 <- renderPlot(plot(pressure))
}
shinyApp(ui, server)
navbarPage(title, ..., id = NULL, selected = NULL, position = c("static-top", "fixed-top", "fixed-bottom"), header = NULL, footer = NULL, inverse = FALSE, collapsible = FALSE, collapsable, fluid = TRUE, responsive = NULL, theme = NULL, windowTitle = title)
Página igual a navbarPage() pero permite embeber un menu en la barra de navegación.
ui <- navbarPage("Shiny - navbarMenu",
tabPanel("Primera Página"),
navbarMenu("Gráficos",
tabPanel("Gráfico 1", plotOutput("plot1")),
tabPanel("Gráfico 2", plotOutput("plot2")))
)
server <- function(input, output) {
output$plot1 <- renderPlot(plot(cars))
output$plot2 <- renderPlot(plot(pressure))
}
shinyApp(ui, server)
Permite crear diferentes pestañas con tabPanel(), cada una de ellas permitirá mostrar vistas independientes.
ui <- fluidPage(
titlePanel("Shiny - tabsetPanel"),
mainPanel(
tabsetPanel(
tabPanel("Plot 1", plotOutput("plot1")),
tabPanel("Plot 2", plotOutput("plot2"))
)
)
)
server <- function(input, output) {
output$plot1 <- renderPlot(plot(cars))
output$plot2 <- renderPlot(plot(pressure))
}
shinyApp(ui, server)
Genera una barra lateral de navegación con pestañas.
ui <- fluidPage(
titlePanel("Shiny - navlistPanel"),
navlistPanel("PANELES",
tabPanel("Primer Panel", plotOutput("plot1")),
tabPanel("Segundo Panel", plotOutput("plot2"))
)
)
server <- function(input, output) {
output$plot1 <- renderPlot(plot(cars))
output$plot2 <- renderPlot(plot(pressure))
}
shinyApp(ui, server)
Control widgets
¿Qué hacemos en el server.R?
En el server es donde debemos realizaremos los cálculos, tablas y gráficos que queremos mostrar en el UI.
Sin orden. Los elementos del server no tienen que seguir un orden de aparición (a diferencia de los del UI).
Funciones. Cada acción o grupo de acciones relacionadas, debe ser definida en una función.
Programación modular. El código que creamos en nuestros scripts ahora debe ir en el server.R.
Los objetos que generemos en el server.R se definen como output$xxx donde xxx es el nombre del objeto.
Para insertar los objetos creados en el server.R en el ui utilizaremos las funciones ...Output('xxx')
## Código en el server.R
output$hist <- renderPlot({
hist(rnorm(input$N))
})
## Código en el ui.R
plotOutput("hist")
Al referirnos a variables introducidas por el usuario mediante widgets definidos en el UI, emplearemos input$xxx, siendo xxx es el nombre indicado en el argumento InputID del widget correspondiente.
Shiny responde de forma inmediata a los cambios introducidos por el usuario pero, ¿siempre queremos esto?
En ocasiones nos interesará realizar un cálculo o un gráfico que dependa de más de una variable, ¿que sucedería si permitimos que Shiny nos de una respuesta instantáneamente?
Las funciones render*() crean una salida para mostrar por pantalla.
Los resultados de estas funciones siempre se guardan en output$xxx.
output$hist <- renderPlot({
hist(rnorm(input$N))
})
Las expresiones reactive() generan un objeto para ser utilizado. Este objeto cambiará de valor cada vez que se modifique algún input$xxx de su interior.
El objeto generado se llama como una función.
data <- reactive({
rnorm(input$N)
})
output$hist <- renderPlot({
hist(data())
})
data <- reactive({
rnorm(input$N)
})
output$hist <- renderPlot({
hist(data(),
main = isolate(input$titulo))
})
ui <- fluidPage(
actionButton(inputId = "accion",
label = "Acción")
)
server <- function(input, output) {
observeEvent(input$accion, {
print(runif(1, 1, 100))
})
}
shinyApp(ui = ui, server = server)
ui <- fluidPage(
numericInput(inputId = "N", label = "Generar número aleatorio entre 0 y:", value = 100, min = 0, max = 300),
actionButton(inputId = "actualizar",
label = "Actualizar"),
textOutput("rnd")
)
server <- function(input, output) {
data <- eventReactive(input$actualizar, {
runif(1, 1, input$N)
})
output$rnd <- renderText({data()})
}
shinyApp(ui = ui, server = server)
-Estos valores reactivos pueden manejarse (usualmente mediante observeEvent())
ui <- fluidPage(
actionButton(inputId = "norm", label = "Normal"),
actionButton(inputId = "unif", label = "Uniforme"),
plotOutput("hist")
)
server <- function(input, output) {
rv <- reactiveValues(data = rnorm(100))
observeEvent(input$norm, { rv$data <- rnorm(100) })
observeEvent(input$unif, { rv$data <- runif(100) })
output$hist <- renderPlot({
hist(rv$data)
}) }
shinyApp(ui = ui, server = server)
RStudio. 2016a. “Hoja de referencia de Shiny.” https://www.rstudio.com/wp-content/uploads/2015/03/shiny-spanish.pdf.
———. 2016b. “Shiny - Tutorial.” https://shiny.rstudio.com/tutorial/lesson1/.
RStudio Team. 2016. RStudio: Integrated Development Environment for R. Boston, MA: RStudio, Inc. http://www.rstudio.com/.
Wickham, H. 2015. Advanced R. Boca Raton, FL: CRC.